package com.itheima.service.impl;

import com.itheima.dao.AccountDao;
import com.itheima.service.AccountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.DefaultTransactionDefinition;

import javax.sql.DataSource;
import java.util.List;

@Service
@Transactional
public class AccountServiceImpl implements AccountService {
    @Autowired
    private AccountDao dao;

    @Autowired
    private AccountServiceClass accountServiceClass;

    /**
     * 编程式事务
     * @param outId
     * @param inId
     * @param money
     *  被事务管理的方法内如果出现异常，不要捕获，要主动抛出异常
     *  这样就会被事务通知捕获，然后做相关的操作；
     *  将异常内部吃掉，导致事务失效
     *   @Transactional
     *      可以作用在方法上，也可以写在类之上
     *      如果写在类之上，那么表示当前类下所有可被增强的方法都会加入事务支持
     *      如果类上和方法上都有@Transactional，事务的特性：
     *          就近原则，范围越小，等级越高
     *     扩展：事务回滚的特点：
     *          只有遇到运行时异常，才能回滚，异常类型必须是RunTimeException
     *          如果是非运行期异常，则不回滚 IOException 默认不会滚
     *     如果我想遇到任何异常都会滚，怎么处理？
     *          rollbackFor = {Exception.class}
     *      如果碰到NullPointException空指针这样的运行异常，不要回滚，如何处理？
     *           noRollbackFor = {NullPointerException.class}
     */
    @Override
    @Transactional(
            isolation = Isolation.REPEATABLE_READ,//设置隔离级别
            timeout = 10,//设置事务超时时间
            readOnly = false,//设置是否是只读事务
            propagation = Propagation.REQUIRED,//设置事务的传播行为
            rollbackFor = {Exception.class},//只要碰到异常就回滚
            noRollbackFor = {NullPointerException.class}
    )
    public void transfer(int outId, int inId, double money) {
            //独立的事务 自动开启 自动提交
            dao.outMoney(outId, money);
            //可能在转账过程中发生意外: 转出执行,转入还未执行
            int i = 1/0;
            //独立的事务 自动开启 自动提交
            dao.inMoney(inId, money);
            //加入事务
            find();
//        try {
//            //独立的事务 自动开启 自动提交
//            dao.outMoney(outId, money);
//            //可能在转账过程中发生意外: 转出执行,转入还未执行
//            int i = 1/0;
//            //独立的事务 自动开启 自动提交
//            dao.inMoney(inId, money);
//        } catch (Exception e) {
//            e.printStackTrace();
//        }
    }


    /**
     * transfer2是事务管理员
     * @param outId
     * @param inId
     * @param money
     */
    @Override
    @Transactional(
            isolation = Isolation.REPEATABLE_READ,//设置隔离级别
            timeout = 10,//设置事务超时时间
            readOnly = false,//设置是否是只读事务
            propagation = Propagation.REQUIRED//设置事务的传播行为
    )
    public void transfer2(int outId, int inId, double money) {
        //转账
        try {
            accountServiceClass.transfer(outId,inId,money);
        } finally {
            //插入日志信息
        /*
            要求：
                1.不能影响主业务事务
                2.主业务抛出异常后，不能影响日志的插入
                3.accountServiceClass.transfer（）方法抛出的异常不能被捕获处理，否则
                事务就不能整体回滚了
         */
            accountServiceClass.insertLog("success2");
        }
    }

    /**
     * 模拟查询
     * @return
     * 如果独立运行find方法，有没有事务？
     *  无事务装填运行
     *  加入
     */
    @Transactional(propagation = Propagation.SUPPORTS)
    public List find(){
        return null;
    }



}
